Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Place Order models and validation #98

Merged
merged 34 commits into from
Jun 17, 2020

Conversation

ChocoShell
Copy link
Contributor

@ChocoShell ChocoShell commented Jun 16, 2020

Creates an orders submodule with the goal of validating the data of the Place Orders API

I created a series of dataclasses that are JSON serializable and will validate the content on initialization. These are available in tdameritrade.orders.models.

Since this uses dataclasses, you need python 3.7+ to run it.

The validation is done by taking the annotated type legId: int and checking if the value is an instance of that type or if it's None

This is all done in the orders.models.base.BaseOrder class. Check there for validation.

There are also builder functions for order legs and orders. I used the Place Order Samples for tests but didn't go much further. These can easily extended to create a nicer interface.

There are a few hiccups.
I saw that price was a str in the samples but the API says it should be an int. This may cause issues with price formatting. We can solve this by creating a new type that will handle this formatting.

It is difficult to validate the members of a list due to some weirdness in the typing library example here, so we may not be able to validate some lists.

Resolves: #60

@timkpaine
Copy link
Owner

this looks fantastic, I had started to do this then gave it up as too much work. are any modifications to the client necessary to plug this in?

@ChocoShell
Copy link
Contributor Author

Hmm, I haven't checked the client too much but this submodule can create a json string, so as long as the placeOrder API accepts JSON strings, it should be fine.

I tested the placeOrder client function with a previous revision of this PR but I haven't done that with this version.

I'll have to do that today and get back to you.

@ChocoShell
Copy link
Contributor Author

Ok, so I made a little script to help me test this out.

import tdameritrade as td
from tdameritrade.orders.order_builder import build_buy_market_stock_order
# You have to import constants with the full path since I didn't make it available in the ./orders/__init__.py.
from tdameritrade.orders.constants import Status

from pprint import pprint


# Authorize TD Client
td_client = td.TDClient(...)

# Load account info to get account Id
td_client.accounts()

account_id = td_client.accountIds[0]

# Creating market buy order json
symbol = "F"  # Chose Ford since it's pretty cheap
quantity = 1

order = build_buy_market_stock_order(symbol, quantity)

pprint(order.asdict())

# Without this, it fails with a 415.  Mentioned in issue #96 
# This may screw up other API calls, so it may have to be reset if you want to try other ones.
td_client.session.headers = {
    "Content-Type": "application/json"
}

# # NOW ENTERING DANGER ZONE AKA TESTING IN PRODUCTION
# # THIS WILL PLACE AN ORDER SO I ONLY TESTED IT AFTER HOURS
# # Placing Order
# try:
# # This will fail to return because the place order API does not return a JSONserializable object on success
# # BUT the order will still go through.  Checked on the site.  You can also check your active orders below.
# # Mentioned in #96
#     response = td_client.placeOrder(account_id, order.json())
#     pprint(response)
# except json.decoder.JSONDecodeError as err:
#     print(err)

# Safe zone
# Print out orders
my_orders = td_client.orders(accountId=account_id)
pprint(my_orders)

# # DANGER ZONE AGAIN
# # THIS WILL CANCEL ALL WORKING ORDERS
# # Orders are a little weird since you will have WORKING and CANCELLED orders
# # so I just went through and cancelled all my cancellable orders.
# for order in td_client.orders(accountId=account_id):
#     if order["status"] == Status.WORKING and order["cancelable"]:
#         response = td_client.cancelOrder(account_id, order["orderId"])
#         pprint(response)

Mentioned issue #96

Haven't tested anything else. Would like to try buy at limit for stocks since I believe the price field will need some work.

@timkpaine
Copy link
Owner

@ChocoShell thanks for testing, I cannot trade so this is very helpful. Maybe some day @TDAmeritrade will allow for trading against a paper account! I'm comfortable with this, I'll merge now

@timkpaine timkpaine merged commit e96be0e into timkpaine:master Jun 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement order builder as utility to build order jsons
2 participants